package rewardservice

import (
	"encoding/json"
	"fmt"
	"games.com/server/internal/pkg/config"
	pkghttp "games.com/server/internal/pkg/http"
	"net/http"
)

type rewardService struct {
	dao    *rewardDAO
	config *config.Config
}

func NewRewardService(config *config.Config) (*rewardService, error) {
	as := &rewardService{config: config}

	dao, err := NewRewardDAO(config)
	if err != nil {
		return nil, fmt.Errorf("failed to new Rewarddao, err:%w", err)
	}
	as.dao = dao

	http.HandleFunc("/AddReward", as.addRewardHandler)
	http.HandleFunc("/DeleteReward", as.deleteRewardHandler)
	http.HandleFunc("/UpdateReward", as.updateRewardHandler)
	http.HandleFunc("/QueryRewardCnt", as.queryRewardCntHandler)
	http.HandleFunc("/QueryReward", as.queryRewardHandler)

	return as, nil
}

type QueryRewardCntRes struct {
	Cnt int32 `json:"cnt"`
}

func (as *rewardService) addRewardHandler(w http.ResponseWriter, r *http.Request) {
	if r.Method == http.MethodOptions {
		pkghttp.AllowCrossRegion(w)
		w.WriteHeader(http.StatusOK)
		return
	}

	if r.Method != http.MethodPost {
		pkghttp.HttpError(w, "only post method is allowed", http.StatusMethodNotAllowed)
		return
	}

	var req Reward
	err := json.NewDecoder(r.Body).Decode(&req)
	if err != nil {
		pkghttp.HttpError(w, err.Error(), http.StatusBadRequest)
		return
	}

	ctx := r.Context()
	err = as.dao.InsertRewards(ctx, &req)
	if err != nil {
		pkghttp.HttpError(w, fmt.Errorf("failed to insert rewards, err:%w", err).Error(), http.StatusInternalServerError)
		return
	}

	resJson, err := json.Marshal(&req)
	if err != nil {
		pkghttp.HttpError(w, err.Error(), http.StatusInternalServerError)
		return
	}

	pkghttp.AllowCrossRegion(w)
	w.WriteHeader(http.StatusOK)
	_, _ = w.Write(resJson)
}

type DeleteRewardReq struct {
	ID int32 `json:"id"`
}

func (as *rewardService) deleteRewardHandler(w http.ResponseWriter, r *http.Request) {
	if r.Method == http.MethodOptions {
		pkghttp.AllowCrossRegion(w)
		w.WriteHeader(http.StatusOK)
		return
	}

	if r.Method != http.MethodPost {
		pkghttp.HttpError(w, "only post method is allowed", http.StatusMethodNotAllowed)
		return
	}

	var req DeleteRewardReq
	err := json.NewDecoder(r.Body).Decode(&req)
	if err != nil {
		pkghttp.HttpError(w, err.Error(), http.StatusBadRequest)
		return
	}

	ctx := r.Context()
	err = as.dao.DeleteRewards(ctx, req.ID)
	if err != nil {
		pkghttp.HttpError(w, fmt.Errorf("failed to delete rewards, err:%w", err).Error(), http.StatusInternalServerError)
		return
	}

	pkghttp.AllowCrossRegion(w)
	w.WriteHeader(http.StatusOK)
}

func (as *rewardService) queryRewardCntHandler(w http.ResponseWriter, r *http.Request) {
	if r.Method == http.MethodOptions {
		pkghttp.AllowCrossRegion(w)
		w.WriteHeader(http.StatusOK)
		return
	}

	if r.Method != http.MethodPost {
		pkghttp.HttpError(w, "only post method is allowed", http.StatusMethodNotAllowed)
		return
	}

	ctx := r.Context()
	cnt, err := as.dao.QueryRewardsCnt(ctx)
	if err != nil {
		pkghttp.HttpError(w, fmt.Errorf("query reward cnt failed, err:%w", err).Error(), http.StatusInternalServerError)
		return
	}
	res := &QueryRewardCntRes{Cnt: cnt}
	resJson, err := json.Marshal(res)
	if err != nil {
		pkghttp.HttpError(w, fmt.Errorf("query reward cnt failed, err:%w", err).Error(), http.StatusInternalServerError)
		return
	}

	pkghttp.AllowCrossRegion(w)
	w.WriteHeader(http.StatusOK)
	_, _ = w.Write(resJson)
}

type QueryRewardReq struct {
	PageCapacity int32 `json:"page_capacity"`
	Page         int32 `json:"page"`
}
type QueryRewardRes struct {
	Rewards []*Reward `json:"rewards"`
}

func (as *rewardService) queryRewardHandler(w http.ResponseWriter, r *http.Request) {
	if r.Method == http.MethodOptions {
		pkghttp.AllowCrossRegion(w)
		w.WriteHeader(http.StatusOK)
		return
	}

	if r.Method != http.MethodPost {
		pkghttp.HttpError(w, "only post method is allowed", http.StatusMethodNotAllowed)
		return
	}

	var req QueryRewardReq
	err := json.NewDecoder(r.Body).Decode(&req)
	if err != nil {
		pkghttp.HttpError(w, err.Error(), http.StatusBadRequest)
		return
	}

	ctx := r.Context()
	rewards, err := as.dao.QueryRewards(ctx, (req.Page-1)*req.PageCapacity, req.PageCapacity)
	if err != nil {
		pkghttp.HttpError(w, fmt.Errorf("failed to query rewards, err:%w", err).Error(), http.StatusInternalServerError)
		return
	}
	res := QueryRewardRes{Rewards: rewards}
	resJson, err := json.Marshal(&res)
	if err != nil {
		pkghttp.HttpError(w, err.Error(), http.StatusInternalServerError)
		return
	}

	pkghttp.AllowCrossRegion(w)
	w.WriteHeader(http.StatusOK)
	_, _ = w.Write(resJson)
}

func (as *rewardService) updateRewardHandler(w http.ResponseWriter, r *http.Request) {
	if r.Method == http.MethodOptions {
		pkghttp.AllowCrossRegion(w)
		w.WriteHeader(http.StatusOK)
		return
	}

	if r.Method != http.MethodPost {
		pkghttp.HttpError(w, "only post method is allowed", http.StatusMethodNotAllowed)
		return
	}

	var req Reward
	err := json.NewDecoder(r.Body).Decode(&req)
	if err != nil {
		pkghttp.HttpError(w, err.Error(), http.StatusBadRequest)
		return
	}

	ctx := r.Context()

	reward, err := as.dao.QueryRewardByID(ctx, req.ID)
	if err != nil {
		pkghttp.HttpError(w, fmt.Errorf("failed to query reward by id, err:%w", err).Error(), http.StatusBadRequest)
		return
	}

	reward.Gm = req.Gm
	reward.Player = req.Player
	reward.Reward = req.Reward
	reward.DateTime = req.DateTime

	err = as.dao.UpdateRewards(ctx, reward)
	if err != nil {
		pkghttp.HttpError(w, fmt.Errorf("failed to insert rewards, err:%w", err).Error(), http.StatusInternalServerError)
		return
	}

	resJson, err := json.Marshal(reward)
	if err != nil {
		pkghttp.HttpError(w, err.Error(), http.StatusInternalServerError)
		return
	}

	pkghttp.AllowCrossRegion(w)
	w.WriteHeader(http.StatusOK)
	_, _ = w.Write(resJson)
}
